# @Time : 2021/4/3 17:35
# @Author : Fioman 
# @Phone : 13149920693
"""
1. 模块说明: 铡刀控制卡的驱动程序
2. 模块功能: 主要用来和铡刀控制卡进行通信
"""
from ctypes import *

import gevent

from db_tools.db_handler import DbHandler
from settings import ZMC_LIB_PATH, AUX_ZMC_LIB_PATH
from tools.hd_logger import HdLogger

bigCutterZmcParamsKey = [
    "XReducerRatio",  # 1.
    "XElecGearRatio",  # 2.
    "XENcoderR",  # 3.
    "XtransporterRH",  # 4.
    "XtransporterPH",  # 5.
    "Xunits",  # 6.
    "XminSpeed",  # 7.
    "XmaxSpeed",  # 8.
    "XworkingSpeed",  # 9.
    "Xaccel",  # 10.
    "Xdecel",  # 11.
    "Xsramp",  # 12.
    "YReducerRatio",  # 13.
    "YElecGearRatio",  # 14
    "YENcoderR",  # 15
    "YtransporterRH",  # 16
    "YtransporterPH",  # 17
    "Yunits",  # 18
    "YminSpeed",  # 19
    "YmaxSpeed",  # 20
    "YworkingSpeed",  # 21
    "Yaccel",  # 22
    "Ydecel",  # 23
    "Ysramp",  # 24
    "Zwidth",  # 25
    "Zunits",  # 26
    "ZminSpeed",  # 27
    "ZmaxSpeed",  # 28
    "ZworkingSpeed",  # 29
    "Zaccel",  # 30
    "Zdecel",  # 31
    "Zsramp",  # 32
    "ZhomeSpeed",  # 33
    "Zhomeaccel",  # 34
    "Zhomedecel",  # 35
    "Rwidth",  # 36
    "Runits",  # 37
    "RminSpeed",  # 38
    "RmaxSpeed",  # 39
    "RworkingSpeed",  # 40
    "Raccel",  # 41
    "Rdecel",  # 42
    "Rsramp",  # 43
    "RhomeSpeed",  # 44
    "Rhomeaccel",  # 45
    "Rhomedecel",  # 46
    "Wwidth",  # 47
    "Wunits",  # 48
    "WminSpeed",  # 49
    "WmaxSpeed",  # 50
    "WworkingSpeed",  # 51
    "Waccel",  # 52
    "Wdecel",  # 53
    "Wsramp",  # 54
    "WhomeSpeed",  # 55
    "Whomeaccel",  # 56
    "Whomedecel",  # 57
    "Wrotationangle",  # 58
]


class BigCutterZmc(object):
    """
    前铡刀控制器驱动类
    """

    def __init__(self):
        self.handleRobot = c_longlong()
        self.logger = HdLogger()
        self.db = DbHandler()
        self.errorMsg = ""
        self.tryAgainDuraion = 0.5  # 通信失败,重新试一遍的时间间隔
        self.ip = "192.168.0.13"
        self.tableName = "bigCutterZmcParams"
        self.isOnline = False
        try:
            self.api = cdll.LoadLibrary(ZMC_LIB_PATH)
            self.aux_api = cdll.LoadLibrary(AUX_ZMC_LIB_PATH)
        except Exception as e:
            self.logger.debug("in bigCutterIndex.__init__() error : {}".format(str(e)))
            self.api = None
            self.aux_api = None

    def __del__(self):
        """
        对象被销毁的时候调用次方法.
        :return:
        """
        try:
            self.close_zmc_conn()
        except Exception as e:
            errorInfo = "in bigCutterIndex.__init__() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

    def check_connect(self):
        try:
            isConnect = self.get_modbus_bit(0, 1)[0]
            isConnect = True if isConnect == 0 else False
            return isConnect
        except Exception as e:
            errorInfo = "in bigCutterIndex.check_connect() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return False

    def cutter_zmc_start(self):
        """
        铡刀控制器启动
        :return:
        """
        bitPos = 0
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_cutter_zmc_start() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return ret

    def cutter_zmc_stop(self):
        """
        铡刀控制器停止
        :return:
        """
        bitPos = 1
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_cutter_zmc_stop() 设置 modbus_bit({}) = {} 失败".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def cutter_zmc_rs_stop(self):
        """
        铡刀控制器设备急停
        :return:
        """
        bitPos = 2
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_cutter_zmc_rs_stop() 设置 modbus_bit({}) = {} 失败".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def cutter_zmc_reset(self):
        """
        铡刀控制器复位,主控制器整体复位
        :return:
        """
        bitPos = 3
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_cutter_zmc_reset() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def cutter_zmc_reset_itself(self):
        """
        铡刀控制器单独复位
        :return:
        """
        bitPos = 2203
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_cutter_zmc_reset_itself() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def is_running(self):
        """
        获取上料控制器是否是运行状态
        :return:
        """
        bitPos = 100
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in big_is_running() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def is_stop_state(self):
        """
        获取上料控制器是否是停止状态
        :return:
        """
        bitPos = 101
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in big_is_stop_state() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def is_rs_stop(self):
        """
        获取上料控制器是否是急停状态
        :return:
        """
        bitPos = 102
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in big_is_rs_stop() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def is_reset_state(self):
        """
        获取上料控制器是否是复位状态
        :return:
        """
        bitPos = 103
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in big_is_reset_state() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def get_allow_take_pic_begin_check(self):
        """
        首检的位置铡刀允许拍照
        :return:
        """
        bitPos = 20
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in big_get_allow_take_pic_begin_check() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def set_allow_begin_check_again_flag(self):
        """
        设置起点检测重新检测一次的逻辑,手动发送20信号.
        :return:
        """
        bitPos = 20
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_allow_begin_check_again_flag() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_allow_final_check_again_flag(self):
        """
        终点检测重新检测一次的逻辑,手动发送
        :return:
        """
        bitPos = 25
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_allow_final_check_again_flag() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_allow_take_pic_begin_check_clear(self):
        """
        首检位置的允许拍照信号清除掉
        :return:
        """
        bitPos = 20
        bitValue = 0
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_allow_take_pic_begin_check_clear() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def get_allow_take_pic_final_check(self):
        """
        终点检测的位置铡刀允许拍照
        :return:
        """
        bitPos = 25
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in big_get_allow_take_pic_final_check() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def set_allow_take_pic_final_check_clear(self):
        """
        终检位置的允许拍照信号清除掉
        :return:
        """
        bitPos = 25
        bitValue = 0
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_allow_take_pic_final_check_clear() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_allow_take_pic_final_check_flag(self):
        """
        终检位置的允许拍照信号清除掉
        :return:
        """
        bitPos = 25
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_allow_take_pic_final_check_clear() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_begin_check_angle_ok(self):
        """
        铡刀起点位置角度ok
        :return:
        """
        bitPos = 21
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_begin_check_angle_ok() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_begin_check_angle_fail(self):
        """
        铡刀起点位置角度NG
        :return:
        """
        bitPos = 22
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_begin_check_angle_fail() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_begin_check_angle_offset(self, angle):
        """
        设置起点检测角度调整值,如果角度太大,就按照最大的那个角度去调整
        :param angle: 要调整的角度
        :return:
        """
        if angle > 20:
            angle = 20
        elif angle < -20:
            angle = -20
        ieeePos = 120
        ieeeValue = angle
        ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
        if ret != 0:
            gevent.sleep(0.1)
            ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
            if ret != 0:
                self.errorMsg = "in big_set_begin_check_angle_offset() 设置 bigCutterIndex modbus_ieee({}) = {} 失败".format(ieeePos, ieeeValue)
                return self.errorMsg
        return ret

    def set_begin_check_move_distance(self, dis):
        """
        设置首检之后,移动到终点之后的距离
        :param dis: 铡刀首检之后要移动的距离
        :return:
        """
        ieeePos = 122
        ieeeValue = dis
        ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
        if ret != 0:
            gevent.sleep(0.1)
            ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
            if ret != 0:
                self.errorMsg = "in big_set_begin_check_move_distance() 设置 bigCutterIndex modbus_ieee({}) = {} 失败".format(ieeePos, ieeeValue)
                return self.errorMsg
        return ret
    
    def set_second_check_move_distance(self, dis):
        """
        设置首检之后,移动到终点之后的距离
        :param dis: 铡刀首检之后要移动的距离
        :return:
        """
        ieeePos = 126
        ieeeValue = dis
        ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
        if ret != 0:
            gevent.sleep(0.1)
            ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
            if ret != 0:
                self.errorMsg = "in big_set_begin_check_move_distance() 设置 bigCutterIndex modbus_ieee({}) = {} 失败".format(ieeePos, ieeeValue)
                return self.errorMsg
        return ret

    def set_final_check_result_ok(self):
        """
        铡刀终点检测结果ok
        :return:
        """
        bitPos = 26
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_final_check_result_ok() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_final_check_result_fail(self):
        """
        铡刀终点检测结果NG
        :return:
        """
        bitPos = 27
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_final_check_result_fail() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_final_check_second_adjust_flag(self):
        """
        设置终点检测进行两次调整的bit位标志
        :return:
        """
        bitPos = 28
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_final_check_second_adjust_flag() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def set_final_check_second_adjust_distance(self, dis):
        """
        终点检测,二次调整的距离
        :param dis:
        :return:
        """
        ieeePos = 124
        ieeeValue = dis
        ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
        if ret != 0:
            gevent.sleep(0.1)
            ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
            if ret != 0:
                self.errorMsg = "in big_set_final_check_second_adjust_distance() 设置 bigCutterIndex modbus_ieee({}) = {} 失败".format(ieeePos, ieeeValue)
                return self.errorMsg
        return ret

    def get_io(self, ioNum):
        value = (c_uint32 * 1)()
        self.aux_api.ZAux_Direct_GetIn.restype = c_int32
        self.aux_api.ZAux_Direct_GetIn.argtype = (c_void_p, c_int32, c_void_p)
        try:
            res = self.aux_api.ZAux_Direct_GetIn(self.handleRobot, c_int32(ioNum), value)
        except Exception as e:
            res = -1
            errorInfo = "in get_io() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        if res != 0:
            self.errorMsg = "in get_output(): ZAux_Direct_GetIn() 执行失败"
        return res, value[:][0]

    def set_cut_board_width(self, boardWidth):
        """
        告诉铡刀,板宽用于控制吹气
        :param boardWidth: 切出来的板的宽度
        :return:
        """
        ieeePos = 200
        ieeeValue = boardWidth
        ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
        if ret != 0:
            gevent.sleep(0.1)
            ret = self.set_modbus_float(ieeePos, 1, [ieeeValue])
            if ret != 0:
                self.errorMsg = "in big_set_cut_board_width() 设置 bigCutterIndex modbus_ieee({}) = {} 失败".format(ieeePos, ieeeValue)
                return self.errorMsg
        return ret

    def set_cut_board_width_finish(self):
        """
        告诉铡刀吹气位置设置完成
        :return:
        """
        bitPos = 1080
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_set_cut_board_width_finish() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def close_door_alarm(self):
        """
        铡刀关闭门报警
        :return:
        """
        bitPos = 200
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_close_door_alarm() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return ret

    def open_door_alarm(self):
        """
        铡刀打开门报警
        :return:
        """
        bitPos = 200
        bitValue = 0
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_close_door_alarm() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return ret

    def set_table(self, start, num, table):
        """
        将数据写入到寄存器的表中
        :param start:表格的起始位置
        :param num:写入的值个数
        :param table:写入的值列表
        :return:
        """
        value = (c_float * num)(0)
        value[:] = table
        self.aux_api.ZAux_Direct_SetTable.restype = c_int32
        self.aux_api.ZAux_Direct_SetTable.argtype = (c_void_p, c_uint32, c_uint32, c_void_p)

        try:
            res = self.aux_api.ZAux_Direct_SetTable(self.handleRobot, c_int32(start), c_int32(num), value)
        except Exception as e:
            res = -1
            errorInfo = "in bigCutterIndex.set_table()  error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in bigCutterIndex.set_table() ZAux_Direct_GetTable() 执行失败"
        return res

    def get_table(self, start, num):
        """
        从底层的表中读取数据table表
        :param start: 读取的起始位置
        :param num: 读取的数据表的个数
        :return:
        """
        value = (c_float * num)()
        self.aux_api.ZAux_Direct_GetTable.restype = c_int32
        self.aux_api.ZAux_Direct_GetTable.argtype = (c_void_p, c_int32, c_int32, c_void_p)
        try:
            res = self.aux_api.ZAux_Direct_GetTable(self.handleRobot, c_int32(start), c_int32(num), value)
        except Exception as e:
            res = -1
            errorInfo = "in bigCutterIndex.get_table() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in bigCutterIndex.get_table() ZAux_Direct_GetTable 执行失败"

        return res, value[:]

    def get_output(self, portPos):
        """
        获取输出口的状态
        :param portPos:
        :return: 结果码:0后者其他 值也是0或者1
        """
        value = (c_uint32 * 1)()
        self.aux_api.ZAux_Direct_GetOp.restype = c_int32
        self.aux_api.ZAux_Direct_GetOp.argtype = (c_void_p, c_int32, c_void_p)
        try:
            res = self.aux_api.ZAux_Direct_GetOp(self.handleRobot, c_int32(portPos), value)
        except Exception as e:
            res = -1
            errorInfo = "in big_get_output() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        if res != 0:
            self.errorMsg = "in big_get_output(): ZAux_Direct_GetOp() 执行失败"
        return res, value[:][0]

    def set_output(self, port, value):
        """
        输出口控制
        :param port:
        :param value:
        :return:
        """
        self.aux_api.ZAux_Direct_SetOp.restype = c_int32
        self.aux_api.ZAux_Direct_SetOp.argtype = (c_void_p, c_int32, c_uint32)
        try:
            res = self.aux_api.ZAux_Direct_SetOp(self.handleRobot, c_int32(port), c_uint32(value))
        except Exception as e:
            res = -1
            errorMsg = "in big_set_output() error: {}".format(str(e))
            print(errorMsg)
            self.logger.debug(errorMsg)
        if res != 0:
            self.errorMsg = "in big_set_output(): 输出口设置失败"
        return res

    def connect_zmc(self, ip):
        """
        铡刀控制器连接接口
        :return:
        """
        if isinstance(ip, type(" ")):
            ip = ip.encode('ascii')
        self.api.ZMC_OpenEth.restype = c_int64
        self.api.ZMC_OpenEth.argtype = (c_char_p, c_void_p)
        status = self.api.ZMC_OpenEth(ip, byref(self.handleRobot))
        if status == 0:
            self.errorMsg = ""
        else:
            self.errorMsg = "铡刀控制器连接失败"
        return status

    def close_zmc_conn(self):
        """
        关闭zmc连接
        :return:
        """
        self.api.ZMC_Close.restype = c_int32
        self.api.ZMC_Close.argtype = c_void_p
        status = self.api.ZMC_Close(self.handleRobot)
        return status

    def set_modbus_bit(self, pos, value):
        """
        设置modbus的位寄存器
        :param pos: 设置的bit位位置
        :param value:设置的值
        :return:
        """
        value = (c_uint8 * 1)(value)
        self.aux_api.ZAux_Modbus_Set0x.restype = c_int32
        self.aux_api.ZAux_Modbus_Set0x.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Set0x(self.handleRobot, c_uint16(pos), c_uint16(1), value)
        except Exception as e:
            res = -1
            print("in big_Zmc(set_modbus_bit)  error: {}".format(e))
            self.logger.debug("in  big_Zmc(set_modbus_bit), error: {}".format(e))

        if res != 0:
            self.errorMsg = "in set_modbus_bit() ZAux_Modbus_Set0x() 执行失败"

        return res

    def get_modbus_bit(self, start, num):
        """
        获取modbus_bit的bit位的值,返回一个列表,里面存放的是所有的bit位的结果值.
        :param start:获取的bit位的起始位置
        :param num:获取的bit位的个数
        :return:
        """
        value = (c_uint8 * num)(0)
        self.aux_api.ZAux_Modbus_Get0x.restype = c_int32
        self.aux_api.ZAux_Modbus_Get0x.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Get0x(self.handleRobot, c_uint16(start), c_uint16(num), value)
        except Exception as e:
            res = -1
            errorInfo = "in big_get_modbus_bit() error:{}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        if res != 0:
            self.errorMsg = "in big_get_modbus_bit() ZAux_Modbus_Get0x() 执行失败"
        return res, value[:]

    def get_axis_postion(self, axisCounts):
        """
         获取轴的坐标,从0轴开始
        :param axisCounts:轴的个数
        :return:返回轴的坐标的值
        """
        value = (c_float * axisCounts)()
        self.aux_api.ZAux_GetModbusDpos.restype = c_int32
        self.aux_api.ZAux_GetModbusDpos.argtype = (c_void_p, c_int32, c_void_p)
        try:
            res = self.aux_api.ZAux_GetModbusDpos(self.handleRobot, c_int32(axisCounts), value)
        except Exception as e:
            res = -1
            errorInfo = "in bigCutterIndex.get_axis_postion() error:{}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        if res != 0:
            self.errorMsg = "in bigCutterIndex.get_axis_postion(): ZAux_GetModbusDpos() 执行失败"

        return res, value[:]

    def set_modbus_byte(self, bytePos, value):
        """
        设置modbus_byte字节寄存器
        :param bytePos:
        :param value:
        :return:
        """
        value = (c_uint16 * 1)(value)
        self.aux_api.ZAux_Modbus_Set4x.restype = c_int32
        self.aux_api.ZAux_Modbus_Set4x.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Set4x(self.handleRobot, c_uint16(bytePos), c_uint16(1), value)
        except Exception as e:
            res = -1
            errorInfo = "in bigCutterIndex.set_modbus_byte() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in bigCutterIndex.set_modbus_byte() ZAux_Modbus_Set4x 执行失败"

        return res

    def set_modbus_float(self, start, counts, values):
        """
        设置modbus_ieee()浮点数的额寄存器,可以设置number个数,然后value
        :param start:modbus_ieee的起点
        :param counts:设置的个数
        :param values:设置的结果值
        :return:
        """
        values = (c_float * counts)(*values)
        self.aux_api.ZAux_Modbus_Set4x_Float.restype = c_int32
        self.aux_api.ZAux_Modbus_Set4x_Float.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Set4x_Float(self.handleRobot, c_uint16(start), c_uint16(counts), values)
        except Exception as e:
            res = -1
            errorInfo = "in bigCutterIndex.set_modbus_float(),error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in bigCutterIndex.set_modbus_float() ZAux_Modbus_Set4x_Float() 执行失败"

        return res

    def excute_zmc_cmd(self, cmd):
        """
        控制执行指令,跟用zdveloper的命令行获取的cmd命令状态是一样的效果
        :param cmd:输入的命令指示
        :return:
        """
        res = b" " * 256
        cmd = cmd.encode('ascii')
        self.api.ZMC_Execute.restype = c_uint32
        self.api.ZMC_Execute.argtype = (c_void_p, c_char_p, c_uint32, c_char_p, c_uint32)
        try:
            value = self.api.ZMC_Execute(self.handleRobot, cmd, 1000, res, 256)
        except Exception as e:
            errorInfo = "in bigCutterIndex.excute_zmc_cmd() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            value = -1
        if value != 0:
            self.errorMsg = "in bigCutterIndex.excute_zmc_cmd() ZMC_Execute() 执行失败"
        return value, res.strip()[:-2]

    def move_abs_four_axis(self, movePos):
        """
        四轴绝对运动,同时移动四个轴,在急停状态下不能移动
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(0,1,2,3)")
        cmd = "moveabs(" + str("%.3f" % movePos[0]) + "," + str("%.3f" % movePos[1]) + "," + str("%.3f" % movePos[2]) + "," + str(
            "%.3f" % movePos[3]) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_x(self, dis):
        """
        裁切机移动X轴
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(0)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_y(self, dis):
        """
        裁切机移动Y轴
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(1)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_z(self, dis):
        """
        裁切机移动Z轴
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(2)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_w(self, dis):
        """
        裁切机移动W轴
        :param dis:移动距离一般是角度
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(3)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_cutter_knife(self, dis):
        """
        移动铡刀刀片
        :param dis:移动的距离
        :return:
        """
        self.excute_zmc_cmd("base(4)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_x(self, dis):
        """
        裁切机移动X轴,绝对移动
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(0)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_y(self, dis):
        """
        裁切机移动Y轴,绝对移动
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(1)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_z(self, dis):
        """
        裁切机移动Z轴,绝对移动
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(2)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_w(self, dis):
        """
        裁切机移动W轴,绝对移动
        :param dis:移动距离一般是角度
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(3)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def get_modbus_float(self, start, counts):
        """
        获取modbus_ieee()的值,可以获取多个值
        :param start: modbus_ieee起始位置
        :param counts: 读取的数量
        :return:
        """
        value = (c_float * counts)()
        self.aux_api.ZAux_Modbus_Get4x_Float.restype = c_int32
        self.aux_api.ZAux_Modbus_Get4x_Float.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Get4x_Float(self.handleRobot, c_uint16(start), c_uint16(counts), value)
        except Exception as e:
            res = -1
            print(e)

        if res != 0:
            self.errorMsg = "ZAux_Modbus_Get4x_Float 执行失败"
        return res, value[:]

    def set_modbus_string(self, msg):
        """
        可以发送字符串,后期用来备用
        :param msg:
        :return:
        """
        maxStrNum = 12
        newMsg = msg
        if len(msg) < maxStrNum:
            n = int((maxStrNum - len(msg)) // 2)
            newMsg = " " * n + msg
        for i in range(0, maxStrNum + 1, 2):
            try:
                b = newMsg[i]
            except Exception as e:
                errorInfo = "in bigCutterIndex.set_modbus_string() error : {}".format(str(e))
                print(errorInfo)
                b = " "
                # 这里不用加日志
            try:
                a = newMsg[i + 1]
            except Exception as e:
                errorInfo = "in bigCutterIndex.set_modbus_string() error : {}".format(str(e))
                print(errorInfo)
                a = " "
            self.set_modbus_byte(1010 + int(i / 2), (ord(a) << 8) | ord(b))

    def set_6pin_flag(self):
        """
        设置单拼板流程
        :return:
        """
        fourJointBit = 40
        sixJointBit = 41
        fourJointVal = 0
        sixJointVal = 1
        ret1 = self.set_modbus_bit(fourJointBit, fourJointVal)
        if ret1 != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret1 = self.set_modbus_bit(fourJointBit, fourJointVal)
            if ret1 != 0:
                self.errorMsg = "in BigCutterZmc.set_6pin_flag() 设置  modbus_bit({}) = {} 失败".format(fourJointBit, fourJointVal)
                return self.errorMsg

        ret2 = self.set_modbus_bit(sixJointBit, sixJointVal)
        if ret2 != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret2 = self.set_modbus_bit(sixJointBit, sixJointVal)
            if ret2 != 0:
                self.errorMsg = "in bigCutterIndex.set_6pin_flag() 设置 modbus_bit ({}) 失败".format(sixJointBit, sixJointVal)
                return self.errorMsg
        ret = 0 if (ret1 == 0 and ret2 == 0) else -1
        return ret

    def set_4pin_flag(self):
        """
        设置双拼板流程
        :return:
        """
        fourJointBit = 40
        sixJointBit = 41
        fourJointVal = 1
        sixJointVal = 0
        ret1 = self.set_modbus_bit(fourJointBit, fourJointVal)
        if ret1 != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret1 = self.set_modbus_bit(fourJointBit, fourJointVal)
            if ret1 != 0:
                self.errorMsg = "in bigCutterZmc.set_4pin_flag() 设置  modbus_bit({}) = {} 失败".format(fourJointBit, fourJointVal)
                return self.errorMsg

        ret2 = self.set_modbus_bit(sixJointBit, sixJointVal)
        if ret2 != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret2 = self.set_modbus_bit(sixJointBit, sixJointVal)
            if ret2 != 0:
                self.errorMsg = "in bigCutterIndex.set_4pin_flag() 设置 modbus_bit ({}) 失败".format(sixJointBit, sixJointVal)
                return self.errorMsg
        ret = 0 if (ret1 == 0 and ret2 == 0) else -1
        return ret

    def open_cutter_cam1_light_source(self):
        """
        打开1号相机的光源.
        :return:
        """
        output = 9
        outputVal = 1
        return self.set_output(output, outputVal)

    def open_cutter_cam2_light_source(self):
        """
        打开2号相机的光源
        :return:
        """
        output = 10
        outputVal = 1
        return self.set_output(output, outputVal)

    def close_cutter_cam1_light_source(self):
        """
        关闭1号相机的光源
        :return:
        """
        output = 9
        outputVal = 0
        return self.set_output(output, outputVal)

    def close_cutter_cam2_light_source(self):
        """
        关闭2号相机的光源
        :return:
        """
        output = 10
        outputVal = 0
        return self.set_output(output, outputVal)

    def reconnect_cutter_zmc(self):
        """
        重新连接铡刀控制器,直接在CutterZmc对象中进行连接,不要再写到produce中去了,它的连接它自己负责就可以了.
        :return:
        """
        try:
            self.close_zmc_conn()
        except Exception as e:
            errorInfo = "in bigCutterIndex.reconnect_cutter_zmc() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        status = self.connect_zmc(self.ip)
        if status == 0:
            self.logger.debug("铡刀控制器连接成功.")
            self.isOnline = True
            res, info = self.set_cutter_zmc_params_to_deivce()
            if res == -1:
                return "error", info
        else:
            self.isOnline = False
        return "ok" if status == 0 else self.errorMsg

    def set_cutter_zmc_params_to_deivce(self):
        """
        加载铡刀控制器参数到底层
        :return:
        """
        try:
            res, paramsDict = self.db.get_cutter_zmc_params(self.tableName)
            if res != "ok":
                return "error", paramsDict
            else:
                paramsDict.pop("key")
                if len(paramsDict.values()) == 0:
                    info = "数据库中无数据,先从底层获取大铡刀的参数数据"
                    print(info)
                    self.logger.debug(info)
                    return self.write_cutter_params_from_zmc_to_mogodb()
                else:
                    # 如果数据库中有数据,就将数据设置进去,避免两个当量的设置
                    paramsList = self.get_cutter_params_value_list_by_dict(paramsDict)
                    if paramsList is None:
                        info = "大铡刀下发参数失败,值列表里面有None值"
                        print(info)
                        self.logger.debug(info)
                        return -1, info
                    else:
                        # 避免两个当量的设置
                        firstList = paramsList[:5]
                        secondList = paramsList[6:17]
                        thirdList = paramsList[18:]
                        firstRet = self.set_modbus_float(0, len(firstList), firstList)
                        secondRet = self.set_modbus_float(12, len(secondList), secondList)
                        thirdRet = self.set_modbus_float(36, len(thirdList), thirdList)

                        if firstRet != 0:
                            gevent.sleep(0.5)
                            firstRet = self.set_modbus_float(0, len(firstList), firstList)
                        if secondRet != 0:
                            gevent.sleep(0.5)
                            secondRet = self.set_modbus_float(12, len(secondList), secondList)
                        if thirdRet != 0:
                            gevent.sleep(0.5)
                            thirdRet = self.set_modbus_float(36, len(thirdList), thirdList)

                        # 如果写入失败就报错,并且返回-1
                        if firstRet != 0 or secondRet != 0 or thirdRet != 0:
                            errorInfo = "in bigCutterIndex.set_cutter_zmc_params_to_deivce() error: 铡刀参数下发失败"
                            print(errorInfo)
                            self.logger.debug(errorInfo)
                            return -1, errorInfo
                        else:
                            okInfo = "铡刀控制器参数下发成功!"
                            print(okInfo)
                            self.logger.debug(okInfo)
                            return 0, "ok"
        except Exception as e:
            errorInfo = "in bigCutterIndex.set_cutter_zmc_params_to_deivce() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return -1, errorInfo

    @staticmethod
    def get_cutter_params_value_list_by_dict(paramsDict):
        """
        根据参数字典的键值列表获取对应的key对应的value列表,为什么不直接用dict的value,是因为dict的value是无序的,key也是无序的,
        不能保证key刚好对应了设备的value值.
        :param paramsDict:
        :return:
        """
        paramsList = [paramsDict.get(key) for key in bigCutterZmcParamsKey]
        if None in paramsList:
            return None
        else:
            return paramsList

    def write_cutter_params_from_zmc_to_mogodb(self):
        """
        从底层获取铡刀的参数,并写入到数据库
        :return:
        """
        ret, val = self.get_modbus_float(0, 58)
        if ret != 0:
            return "-1", "in bigCutterIndex.write_cutter_params_from_zmc_to_mogodb() error: 从底层读取数据失败!"
        else:
            cutterZmcParams = dict(zip(bigCutterZmcParamsKey, val))
            query = {
                "key": "1"
            }
            newValues = {
                "$set": cutterZmcParams
            }
            return self.db.update_data(self.tableName, query, newValues)

    def web_request_get_cutter_zmc_params(self):
        """
        前端界面请求铡刀的参数
        :return:
        """
        try:
            res, paramsDict = self.db.get_cutter_zmc_params(self.tableName)
            if res != "ok":
                return "数据库错误,获取的数据为空"
            else:
                return [paramsDict]
        except Exception as e:
            errorInfo = "in bigCutterIndex.web_request_get_cutter_zmc_params() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return errorInfo

    def web_request_save_cutter_zmc_params(self, newParams):
        """
        界面上点击了保存铡刀控制器参数
        :param newParams: 新的参数
        :return:
        """
        try:
            query = {
                "key": "1"
            }
            newValues = {
                "$set": newParams
            }
            res, info = self.db.update_data(self.tableName, query, newValues)
            connected = self.check_connect()
            if connected:
                res, info = self.set_cutter_zmc_params_to_deivce()
                if res == -1:
                    return info
            return "ok" if res == "ok" else info
        except Exception as e:
            errorInfo = "in bigCutterIndex.web_request_save_cutter_zmc_params() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return errorInfo

    def web_request_cutter_zmc_stop(self):
        """
        点击停止设备
        :return:
        """
        ret = self.cutter_zmc_stop()
        return "ok" if ret == 0 else ret

    def get_io_in_state(self,inPos):
        """
        获取输入口的状态
        :param inPos:
        :return:
        """
        cmd = "?in(" + str(inPos) + ")"
        val = self.excute_zmc_cmd(cmd)[1]
        val = int(val,base=2)
        return val

    def get_door_start(self):
        resVal1 = self.get_io_in_state(13)
        resVal2 = self.get_io_in_state(14)
        return resVal1, resVal2


    def open_buzzer_alarm(self):
        """
        打开蜂鸣器报警
        :return:
        """
        if not self.isOnline:
            return
        bitPos = 110
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_open_buzzer_alarm() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return ret

    def close_buzzer_alarm(self):
        """
        关闭蜂鸣器报警
        :return:
        """
        if not self.isOnline:
            return
        bitPos = 110
        bitValue = 0
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in big_close_buzzer_alarm() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return ret


if __name__ == '__main__':
    pass
